/*
 * Saphre - Suffix Arrays for Phrase Extraction
 * Copyright (C) 2013 
 * Dale Gerdemann - Tübingen, Germany 
 * Niko Schenk - Frankfurt am Main, Germany
 * All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package saphre.concordance;

import util.Interval;
import saphre.core.Store;
import saphre.core.SuffixArray;
import util.IntString;
import util.IntTST;
import java.io.Serializable;


/**
 * This class implements a concordance search and prints maximal repeats
 * for a given query.
 * 
 * Experimental. Do not use.
 * 
 * @author Dale Gerdemann, Niko Schenk
 */
public class Concordance implements Serializable {

    boolean filter;
    String target;
    Store store;
    int N;
    int Z = 18;  // indentation

    public Concordance(Store store) {
        // this.tc = tc;
        this.store = store;
        // Context.store = store;
        N = store.text.length - 1;
        this.Z = Z + 20;
        // filter = true;
    }
    
    /**
     * 
     * @param target 
     */
    public void setTarget(String target) {
        this.target = target;
    }


    /**
     *
     * @param inter
     * @param lcp
     * @param pa
     * @param targetLcp
     * @param sa
     * @return
     */
    public IntTST traverse(Interval inter, int lcp, SuffixArray pa,
                    int targetLcp, SuffixArray sa) {

        if (inter.trivial()) {
            return new IntTST();
        }
        else {
            int mid = inter.mid(pa.getCldtab());
            int midLcp = inter.lcp(mid, pa.getLcptab());


            int increase = 0;
            if (lcp < midLcp) {
                increase = midLcp - lcp;
            }
            int top = pa.getSuftab()[mid];

            int bot = top - midLcp + 1;

            boolean reject = false;

            IntTST st1 = null;
            IntTST st2 = null;
            if (!reject) {
                Interval left = new Interval(inter.lb(), mid - 1);
                Interval right = new Interval(mid, inter.rb());
                st1 = traverse(left, midLcp, pa, targetLcp, sa);
                st2 = traverse(right, midLcp, pa, targetLcp, sa);
            }

            if (st1.size() < st2.size()) {
                for (IntString s : st1.keys()) {
                    st2.put(s);
                }

            }
            else {
                for (IntString s : st2.keys()) {
                    st1.put(s);
                }
            }

            if (!reject && increase > 0 && midLcp >= targetLcp) {
                int begin = bot;
                int length = midLcp;
                String cache = store.toStringL(begin, length - targetLcp);
                int[] leftArr = store.toArrayL(begin, length);
                Interval rInterval = sa.search(store.toArrayL(begin, length));
               
                boolean success = traverse2(rInterval, midLcp - 1, sa, cache, midLcp, st2, leftArr);
                // if (!success) {
                // System.out.printf("%"+Z+"s  %s\n", cache, target);
                // }
            }
            return st2;
        }
    }

    /**
     * 
     * @param inter
     * @param lcp
     * @param sa
     * @param leftPart
     * @param rLcp
     * @param st
     * @param leftArr
     * @return 
     */
    public boolean traverse2(Interval inter, int lcp, SuffixArray sa, String leftPart,
                      int rLcp, IntTST st, int[] leftArr) {   
        
        if (inter.trivial()) {
            return false;
        }
        else {
            boolean success = false;

            int mid = inter.mid(sa.getCldtab());
            int midLcp = inter.lcp(mid, sa.getLcptab());

            int increase = 0;
            if (lcp < midLcp) {
                increase = midLcp - lcp;
            }
            int top = sa.getSuftab()[mid];
            int bot = top + midLcp;
            boolean reject = false;

            if (!reject && increase > 0) {
                int[] pat = store.toArray(top + rLcp, bot);
                if (!st.contains(pat)) {
                    success = true;
                    st.put(pat);
                    System.out.printf("%" + Z + "s  %s   %s\n",
                            leftPart, target,
                            store.toString(top + rLcp, bot));
                    System.out.println("Interval: " + inter.toString()
                                    + " docdist: " + inter.docDist(sa, store)
                                    );
                    
                    for(int tf = 0; tf < inter.tf(); tf++) {
                        // Das hier ist der Startindex eines jeden Repeats.
                        System.out.println("start index: " + sa.getSuftab()[inter.lb()+tf]);
                        // Jetzt gehe im Suftab einfach X nach links und X + länge des Repeats nach rechts.
                        // Und printe.
                        int startIndex = sa.getSuftab()[inter.lb()+tf];
                        // loc - leftcontext länge . allerdings muss hier acht gegeben werden auf den index out of bounds.
                        
                        String ngram = store.toString(startIndex - 1, (startIndex + 4)); 
                        System.out.println("kwic: " + ngram);
                    }
                }
            }
            boolean success1 = false;
            boolean success2 = false;
            if (!reject) {
                Interval left = new Interval(inter.lb(), mid - 1);
                Interval right = new Interval(mid, inter.rb());
                success1 = traverse2(left, midLcp, sa, leftPart, rLcp, st, leftArr);
                success2 = traverse2(right, midLcp, sa, leftPart, rLcp, st, leftArr);
            }
            return (success || success1) || success2;
        }
    }
    
    
    /**
     * 
     * @param pa
     * @param sa
     * @param query 
     */
    public void getKwic(SuffixArray pa,
                     SuffixArray sa, String query) {
       
        // Find interval.
        Interval interval = sa.search(query, store);
        int lcp = sa.getLcp(interval);
        int loc = sa.getSuftab()[interval.lb()];
        String ngram = store.toString(loc, (loc + lcp));

        //System.out.println("--> " + ngram + " query: " + query);
        // ngram's tokens are separated by " " (defined in Store.java) toString().


        System.out.println("ngram: " + ngram);
        System.out.println("query: " + query);


        int ngramsize = loc - (loc - lcp); 
        int[] generalngram = new int[ngramsize];
        int ngramindex = 0;
        // Collect this ngram. Every array index is occupied by an individual token/character.
        for (int l = 0; l < ngramsize; l++) {
            generalngram[l] = sa.getText()[loc + ngramindex];
            ngramindex++;
        }

        System.out.println("Interval: " + interval.toString()
                + " Docdist: " + interval.docDist(sa, store) + "\n");

        for (int tfCnt = 0; tfCnt < interval.tf(); tfCnt++) {
            // This is the start index of a repeat.
            System.out.print("Start index: " + sa.getSuftab()[interval.lb() + tfCnt] + " --> ");
            // Advance x positions to the left in suftab
            // and x + length of repeat to the right.
            int startIndex = sa.getSuftab()[interval.lb() + tfCnt];
            System.out.println("in document: " + store.docNameOfPos(startIndex));
            // loc - leftcontext length . 
            // TODO: Check array index out of bounds.
            
            String hit = store.toString(startIndex, (startIndex + lcp));
            //System.out.println("Hit: " + hit);            
            
            int leftContextSize = 2;
            String leftContext = store.toString(startIndex - leftContextSize, (startIndex));
            //System.out.println("Left context: " +  leftContext);
            
            int rightContextSize = 2;
            String rightContext = store.toString(startIndex + lcp, (startIndex + lcp + rightContextSize));
            //System.out.println("Right context: " +  rightContext);
            
            System.out.println("KWIC: " + leftContext + "\t" + hit + "\t" + rightContext + "\n");
        }
    }
}